创建时间: | 2015/8/25 0:01 |
来源: | http://www.oschina.net/question/224858_36864?sort=time |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | package canghailan.reflect; import canghailan.cache.ConcurrentLRUCache; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; /** * <a href="http://my.oschina.net/arthor" class="referer" target="_blank">@author</a> canghailan 2012-01-13 23:06 */ public class Methods { private static Map<MethodID, Method[]> methodsCache = new ConcurrentLRUCache<>(); private static ThreadLocal<MethodID> methodID = new ThreadLocal<MethodID>() { protected MethodID initialValue() { return new MethodID(); } }; //################################################################################ public static Method[] lookupMethods(Class<?> clazz, String name) { Method[] methods = methodsCache.get(methodID.get().set(clazz, name)); if (methods == null ) { // methods has the same name List<Method> list = new LinkedList<>(); for (Method method : clazz.getMethods()) { if (method.getName().equals(name)) { list.add(method); } } methods = list.toArray( new Method[list.size()]); // sort by param length Arrays.sort(methods, new Comparator<Method>() { @Override public int compare(Method a, Method b) { return a.getParameterTypes().length - b.getParameterTypes().length; } }); // cache methodsCache.put( new MethodID(clazz, name), methods); } return methods; } public static Method lookupMethod(Class<?> clazz, String name, Object... params) throws NoSuchMethodException { Method acceptMethod = null ; for (Method method : lookupMethods(clazz, name)) { // skip methods if (method.getParameterTypes().length < params.length) { continue ; } // lookup finished if (method.getParameterTypes().length > params.length) { break ; } int diff = checkAssignable(method.getParameterTypes(), params); // not match if (diff < 0 ) { continue ; } if (diff == 0 ) { return method; } // better method if (acceptMethod == null || checkAssignable(acceptMethod.getParameterTypes(), method.getParameterTypes()) > 0 ) { acceptMethod = method; } } if (acceptMethod == null ) { throw new NoSuchMethodException(invokeToString(clazz, name, params)); } return acceptMethod; } private static int checkAssignable(Class<?> type, Class<?> clazz) { if (clazz == null || type.equals(clazz)) { return 0 ; } if (type.isAssignableFrom(clazz)) { return 1 ; } return - 1 ; } private static int checkAssignable(Class<?>[] types, Class<?>[] classes) { if (classes == null || types.length != classes.length) { return - 1 ; } int diffs = 0 ; for ( int i = 0 ; i < classes.length; ++i) { int diff = checkAssignable(types[i], classes[i]); if (diff < 0 ) { return - 1 ; } diffs += diff; } return diffs; } private static int checkAssignable(Class<?>[] classes, Object[] objects) { if (objects == null || classes.length != objects.length) { return - 1 ; } int diffs = 0 ; for ( int i = 0 ; i < classes.length; ++i) { int diff = checkAssignable(classes[i], objects[i] == null ? null : objects[i].getClass()); if (diff < 0 ) { return - 1 ; } diffs += diff; } return diffs; } private static String invokeToString(Class<?> clazz, String method, Object... params) { StringBuilder buffer = new StringBuilder(); buffer.append(clazz.getName()).append( '$' ); buffer.append(method).append( '(' ); for (Object param : params) { buffer.append(param).append( ", " ); } buffer.setLength(buffer.length() - ", " .length()); buffer.append( ')' ); return buffer.toString(); } //################################################################################ @SuppressWarnings ( "unchecked" ) public static <T> T invoke(Object object, String method, Object... params) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { return (T) lookupMethod(object.getClass(), method, params).invoke(object, params); } @SuppressWarnings ( "unchecked" ) public static <T> T invoke(Class<?> clazz, String method, Object... params) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { return (T) lookupMethod(clazz, method, params).invoke( null , params); } //################################################################################ private static class MethodID { Class<?> clazz; String name; MethodID() { } MethodID(Class<?> clazz, String name) { this .clazz = clazz; this .name = name; } MethodID set(Class<?> clazz, String name) { this .clazz = clazz; this .name = name; return this ; } @Override public boolean equals(Object o) { if ( this == o) { return true ; } if (o instanceof MethodID) { MethodID methodID = (MethodID) o; return Objects.equals(clazz, methodID.clazz) && Objects.equals(name, methodID.name); } return false ; } @Override public int hashCode() { int result = Objects.hashCode(clazz); result = 31 * result + Objects.hashCode(name); return result; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | package canghailan.reflect; import canghailan.cache.ConcurrentLRUCache; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; import java.util.Objects; /** * <a href="http://my.oschina.net/arthor" class="referer" target="_blank">@author</a> canghailan 2012-01-13 23:06 */ public class Fields { private static Map<FieldID, Field> fieldCache = new ConcurrentLRUCache<>(); private static Map<FieldID, Method> getterCache = new ConcurrentLRUCache<>(); private static ThreadLocal<FieldID> fieldID = new ThreadLocal<FieldID>() { protected FieldID initialValue() { return new FieldID(); } }; private static ThreadLocal<StringBuilder> buffer = new ThreadLocal<StringBuilder>() { protected StringBuilder initialValue() { return new StringBuilder(); } }; //################################################################################ public static Field lookupField(Class<?> clazz, String name) throws NoSuchFieldException { assert clazz != null ; // using cache FieldID id = fieldID.get().set(clazz, name); if (fieldCache.containsKey(id)) { return fieldCache.get(id); } // lookup and cache for (Class<?> clz = clazz; clz != null ; clz = clz.getSuperclass()) { for (Field field : clz.getDeclaredFields()) { if (field.getName().equals(name)) { fieldCache.put( new FieldID(clazz, name), field); return field; } } } throw new NoSuchFieldException(clazz.getName() + "." + name); } //################################################################################ public static String getterOrSetter(String getOrSet, String field) { // build get...|is...|set... StringBuilder buf = buffer.get(); buf.setLength( 0 ); buf.append(getOrSet).append(field) .setCharAt(getOrSet.length(), Character.toUpperCase(field.charAt( 0 ))); return buf.toString(); } @SuppressWarnings ( "unchecked" ) public static <T> T get(Object object, String field) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { // using cache FieldID id = fieldID.get().set(object.getClass(), field); Method getter = getterCache.get(id); if (getter != null ) { return (T) getter.invoke(object); } if (getterCache.containsKey(id)) { throw new NoSuchMethodException( "getter: " + object.getClass().getName() + "." + field); } // lookup get and cache getter = Methods.lookupMethod(object.getClass(), getterOrSetter( "get" , field)); if (getter != null ) { getterCache.put( new FieldID(object.getClass(), field), getter); return (T) getter.invoke(object); } // maybe boolean, lookup is and cache if (field.startsWith( "is" ) && Character.isUpperCase(field.charAt( "is" .length()))) { getter = Methods.lookupMethod(object.getClass(), getterOrSetter( "is" , field.substring( "is" .length()))); } else { getter = Methods.lookupMethod(object.getClass(), getterOrSetter( "is" , field)); } if (getter != null ) { getterCache.put( new FieldID(object.getClass(), field), getter); return (T) getter.invoke(object); } // no such method, cache getterCache.put( new FieldID(object.getClass(), field), null ); throw new NoSuchMethodException( "getter: " + object.getClass().getName() + "." + field); } public static void set(Object object, String field, Object value) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { Methods.invoke(object, getterOrSetter( "set" , field), value); } //################################################################################ @SuppressWarnings ( "unchecked" ) public static <T> T directGet(Object object, String fieldName) throws NoSuchFieldException, IllegalAccessException { Field field = lookupField(object.getClass(), fieldName); boolean accessible = field.isAccessible(); field.setAccessible( true ); Object value = field.get(object); field.setAccessible(accessible); return (T) value; } public static void directSet(Object object, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException { Field field = lookupField(object.getClass(), fieldName); boolean accessible = field.isAccessible(); field.setAccessible( true ); field.set(object, value); field.setAccessible(accessible); } //################################################################################ public static void copy(Object src, Object dst, String... fields) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { if (src.getClass().equals(dst.getClass())) { for (String name : fields) { Field field = lookupField(src.getClass(), name); boolean accessible = field.isAccessible(); field.setAccessible( true ); field.set(dst, field.get(dst)); field.setAccessible(accessible); } } else { for (String name : fields) { set(dst, name, get(src, name)); } } } public static <T> void copy(T src, T dst) throws IllegalAccessException { for (Class<?> clz = src.getClass(); clz != null ; clz = clz.getSuperclass()) { for (Field field : clz.getDeclaredFields()) { boolean accessible = field.isAccessible(); field.setAccessible( true ); field.set(dst, field.get(dst)); field.setAccessible(accessible); } } } //################################################################################ private static class FieldID { Class<?> clazz; String name; FieldID() { } FieldID(Class<?> clazz, String name) { this .clazz = clazz; this .name = name; } FieldID set(Class<?> clazz, String name) { this .clazz = clazz; this .name = name; return this ; } @Override public boolean equals(Object o) { if ( this == o) { return true ; } if (o instanceof FieldID) { FieldID fieldID = (FieldID) o; return Objects.equals(clazz, fieldID.clazz) && Objects.equals(name, fieldID.name); } return false ; } @Override public int hashCode() { int result = Objects.hashCode(clazz); result = 31 * result + Objects.hashCode(name); return result; } } } |
如果我没猜错,你应该指的是反射方法时overload的处理吧。我在Methods里处理了这种情况。
1 | public static Method lookupMethod(Class<?> clazz, String name, Object... params) |
同名方法选择最精确的方法。
就我的了解,反射的时候int之类的都应该是boxing为Integer等包装类型处理的。